package handler

import (
	"context"
	"crypto/sha512"
	"fmt"
	"github.com/anaskhan96/go-password-encoder"
	"github.com/golang/protobuf/ptypes/empty"
	"go.uber.org/zap"
	"google.golang.org/grpc/codes"
	"google.golang.org/grpc/status"
	"google.golang.org/protobuf/types/known/emptypb"
	"gorm.io/gorm"
	"mxshop_srvs/user_srv/global"
	"mxshop_srvs/user_srv/model"
	"mxshop_srvs/user_srv/proto"
	"strings"
	"time"
)

type UserService struct {
}

// GetUserList 获取用户列表
func (u *UserService) GetUserList(ctx context.Context, req *proto.PageInfo) (*proto.UserListResponse, error) {
	var users []model.User
	var total int64

	fmt.Println("用户列表")
	// 统计总数
	global.DB.Model(&model.User{}).Count(&total)

	// 分页查询
	global.DB.Scopes(Paginate(int(req.Pn), int(req.PSize))).Find(&users)

	// 构造响应
	rsp := &proto.UserListResponse{Total: int32(total)}
	for _, user := range users {
		rsp.Data = append(rsp.Data, ModelToResponse(user))
	}
	return rsp, nil
}

func ModelToResponse(user model.User) *proto.UserInfoResponse {
	//在grpc的message中字段有默认值，你不能随便赋值nil进去，容易出错
	//这里要搞清， 哪些字段是有默认值
	userInfoRsp := proto.UserInfoResponse{
		Id:       user.ID,
		PassWord: user.PassWord,
		NickName: user.NickName,
		Gender:   user.Gender,
		Role:     int32(user.Role),
		Mobile:   user.Mobile,
	}
	if user.Birthday != nil {
		userInfoRsp.BirthDay = uint64(user.Birthday.Unix())
	}
	return &userInfoRsp
}

func Paginate(page, pageSize int) func(db *gorm.DB) *gorm.DB {
	return func(db *gorm.DB) *gorm.DB {
		if page <= 0 {
			page = 1
		}

		switch {
		case pageSize > 100:
			pageSize = 100
		case pageSize <= 0:
			pageSize = 10
		}

		offset := (page - 1) * pageSize
		return db.Offset(offset).Limit(pageSize)
	}
}

func (u *UserService) GetUserByMobile(ctx context.Context, req *proto.MobileRequest) (*proto.UserInfoResponse, error) {
	//通过手机号码查询用户
	var user model.User
	result := global.DB.Where(&model.User{Mobile: req.Mobile}).First(&user)
	//是否查询到该用户
	if result.RowsAffected == 0 {
		return nil, status.Errorf(codes.NotFound, "用户不存在")
	}
	if result.Error != nil {
		//数据库异常
		return nil, result.Error
	}
	userInfoRsp := ModelToResponse(user)

	return userInfoRsp, nil
}
func (u *UserService) GetUserById(ctx context.Context, req *proto.IdRequest) (*proto.UserInfoResponse, error) {
	//通过Id查询用户
	var user model.User
	result := global.DB.First(&user, req.Id)
	//是否查询到该用户
	if result.RowsAffected == 0 {
		return nil, status.Errorf(codes.NotFound, "用户不存在")
	}
	if result.Error != nil {
		//数据库异常
		return nil, result.Error
	}
	userInfoRsp := ModelToResponse(user)
	return userInfoRsp, nil
}

func (u *UserService) CreateUser(ctx context.Context, req *proto.CreateUserInfo) (*proto.UserInfoResponse, error) {
	/**
	在 CreateUser 方法中，创建了新用户，但 ModelToResponse 函数使用的 user 对象是旧的。global.DB.Create 不会自动更新传入的 user 对象字段。
	修改建议
	在创建用户后，使用 global.DB.First 或 Create 的返回值更新 user 对象，确保包含新生成的 ID 和其他字段。
	*/

	// 检查用户是否存在
	var user model.User
	result := global.DB.Where(&model.User{Mobile: req.Mobile}).First(&user)
	if result.RowsAffected == 1 {
		return nil, status.Errorf(codes.AlreadyExists, "用户已存在")
	}

	// 加密密码
	options := &password.Options{
		SaltLen: 16, Iterations: 100, KeyLen: 32, HashFunction: sha512.New,
	}
	salt, encodedPwd := password.Encode(req.PassWord, options)
	newPassword := fmt.Sprintf("$pbkdf2-sha512$%s$%s", salt, encodedPwd)

	// 创建用户并更新 user 对象
	user = model.User{
		Mobile:   req.Mobile,
		NickName: req.NickName,
		PassWord: newPassword,
	}
	result = global.DB.Create(&user)
	if result.Error != nil {
		return nil, status.Errorf(codes.Internal, result.Error.Error())
	}

	// 返回填充了新数据的用户信息
	userInfoRsp := ModelToResponse(user)
	return userInfoRsp, nil
}

func (u *UserService) UpdateUser(ctx context.Context, req *proto.UpdateUserInfo) (*emptypb.Empty, error) {
	var user model.User
	// 检查用户是否存在
	updates := map[string]interface{}{}
	if req.NickName != "" {
		updates["NickName"] = req.NickName
	}
	if req.Gender != "" {
		updates["Gender"] = req.Gender
	}
	if req.BirthDay > 0 {
		birthDay := time.Unix(int64(req.BirthDay), 0)
		updates["Birthday"] = birthDay
	}

	result := global.DB.Model(&user).Where("id = ?", req.Id).Updates(updates)
	if result.Error != nil {
		// 数据库操作出错
		return nil, status.Errorf(codes.Internal, result.Error.Error())
	}

	return &empty.Empty{}, nil
}
func (u *UserService) CheckPassWord(ctx context.Context, req *proto.CheckPassWordInfo) (*proto.CheckResponse, error) {
	// 校验密码
	options := &password.Options{
		SaltLen:      16,
		Iterations:   100,
		KeyLen:       32,
		HashFunction: sha512.New,
	}
	// 分割加密密码信息
	passwordInfo := strings.Split(req.EncryptedPassword, "$")
	if len(passwordInfo) < 4 {
		zap.S().Errorw("密码格式不正确", "encrypted_password", req.EncryptedPassword)
		return nil, fmt.Errorf("密码格式不正确")
	}
	// 验证密码
	check := password.Verify(req.Password, passwordInfo[2], passwordInfo[3], options)
	// 返回验证结果
	return &proto.CheckResponse{Success: check}, nil
}
